package it.happyisland.framework.web.core;

import it.happyisland.framework.web.Bean;
import it.happyisland.framework.web.Param;
import it.happyisland.framework.web.PathVariable;
import it.happyisland.framework.web.Session;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class Parameters {
	
	private Converter converter;
	
	public Parameters(Converter converter) {
		super();
		this.converter = converter;
	}
	
	
	public Object[] resolve(HttpServletRequest req, HttpServletResponse resp, FilterChain chain, Action action) throws ServletException{
		Class<?>[] parameterTypes = action.method.getParameterTypes();
		Annotation[][] parametersAnnotations = action.method.getParameterAnnotations(); 
		Object[] parameters = new Object[parameterTypes.length];
		for(int i = 0; i < parameters.length; i++){
			if(parametersAnnotations[i].length > 1){
				throw new ServletException(parameterTypes[i].getSimpleName() + " in method " + action.method.getName() + " can be annotated only with one Annotation");
			}
			Annotation annotation = parametersAnnotations[i].length > 0 ? parametersAnnotations[i][0] : null;
			parameters[i] = resolveParameter(req, resp, chain, action.pathVariables, parameterTypes[i], annotation);
		}
		return parameters;
	}

	private Object resolveParameter(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Map<String,String> pathVariables, Class<?> type, Annotation annotation) throws ServletException {
		if(annotation instanceof PathVariable){
			PathVariable pv = (PathVariable) annotation;
			String pvParam = pathVariables.get(pv.value());
			return converter.convert(pvParam, type);
		}
		if(annotation instanceof Param){
			Param param = (Param) annotation;
			String requestParameter = request.getParameter(param.value());
			return converter.convert(requestParameter, type);
		}
		
		if(annotation instanceof Bean){
			Object instance = Reflection.newInstance(type);
			for (Method method : type.getDeclaredMethods()) {

				if (Reflection.isSetter(method)) {
					String name = Reflection.getPropertyName(method);
					String value = request.getParameter(name);
					if(value != null) {
						Object injectValue = converter.convert(value, method.getParameterTypes()[0]);
						Reflection.invoke(instance, method, injectValue);
					}
				}
			}
			return instance;
		}
		
		if(annotation instanceof Session){
			Session param = (Session) annotation;
			return request.getSession().getAttribute(param.value());
		}
		if(type.equals(HttpServletRequest.class)){
			return request;
		}
		if(type.equals(HttpServletResponse.class)){
			return response;
		}
		if(type.equals(FilterChain.class)){
			return chain;
		}
		
		return null;
	}
}
